﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using baselib;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Logging;

namespace Webchenzd.Controllers
{
    [Route("File")]
    [ApiController]
    public class FileVersionController : ControllerBase
    {


        private ILogger<FileVersionController> _logger;

        public FileVersionController(ILogger<FileVersionController> logger)
        {
            _logger = logger;
        }

        const string UpdateConfigFile = "UpdateConfigFile.json";

        
        /// <summary>
        /// 下载对应uniquename的版本文件信息
        /// </summary>
        /// <param name="uniquename"></param>
        /// <returns>返回一个json串</returns>
        [HttpGet("GetVersion/{uniquename}")]
        public string GetVersion(string uniquename)
        {
            try
            {               
                _logger.LogInformation(Request.Host.ToString()+"GetVersion "+ uniquename);
                //先判断是否存在uniquename文件夹
                uniquename = "FileServer\\" + uniquename;
                if (Directory.Exists(uniquename))
                {

                    var url = Directory.GetCurrentDirectory() + $"\\{uniquename}\\" + UpdateConfigFile;
                    using (var stream = System.IO.File.OpenRead(url))
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        return reader.ReadToEnd();
                    }
                }
                else
                {
                    return "";
                }
            }
            catch (Exception e)
            {

                _logger.LogError(e.Message);
                return null;
            }
        }

        /// <summary>
        /// Post 提交本地文件夹力的所有文件信息 json格式
        /// </summary>
        /// <returns>返回服务器对比后，判断需要上传文件列表</returns>
        [HttpPost("CheckNeedUpload")]
        public async Task<string> CheckNeedUpload()
        {
            CheckNeedUploadResult ret = new CheckNeedUploadResult();
            string jsonstr = "";
            using (var reader = new StreamReader(Request.Body, Encoding.UTF8))
            {

                jsonstr = await reader.ReadToEndAsync();

            }
            var tvlocal = Newtonsoft.Json.JsonConvert.DeserializeObject<TotalFileVersion>(jsonstr);
            string uniquename = tvlocal.UniqueName;
                
            jsonstr = GetVersion(uniquename);
            if (string.IsNullOrEmpty(jsonstr)) //server没有，即为第一次上传
            {
                ret.NeedUpdate = true;
                foreach(var item in tvlocal.FileUnits)
                {
                    ret.NeedUploadFiles.Add(item.FileRelativePath);
                }
                return Newtonsoft.Json.JsonConvert.SerializeObject(ret);

            }


            var tvServer = Newtonsoft.Json.JsonConvert.DeserializeObject<TotalFileVersion>(jsonstr);

            var rootpath = "";
            //step1 本地绝对路径转化成相对路径,获得rootpath
            foreach(var fileunit in tvlocal.FileUnits )
            {
                var dir= Path.GetDirectoryName(fileunit.FileRelativePath);
                if(rootpath=="" || dir.Length <rootpath.Length )
                {
                    rootpath = dir;
                }
            }

            //step2 ,比较，本地都是比server端要新的，不可能旧，但也可能删除了部分文件
            foreach (var fileunit in tvlocal.FileUnits)
            {
                var fileshortname = PathHelper.GetRelitivePath(fileunit.FileRelativePath, rootpath);
                if (fileshortname == UpdateConfigFile)
                {
                    continue;
                }


                var fileunitServer = tvServer.FileUnits.FirstOrDefault((file) => { return file.FileRelativePath == fileshortname; });

                //如果tv中不存在，则为新增的文件
                if (fileunitServer == null)
                {
                    ret.NeedUpdate = true;
                    ret.NeedUploadFiles.Add( fileunit.FileRelativePath);
                }
                else//tv中存在，则比较，若不一样则需要跟新
                {
                    if (fileunitServer.FileSize != fileunit.FileSize || fileunit.LastUpdateTime != fileunit.LastUpdateTime)
                    {
                        ret.NeedUpdate = true;
                        ret.NeedUploadFiles.Add(fileunit.FileRelativePath);
                    }
                }

                //server中存在但是local中不存在的应该删除，暂时不做

            }
            

            return   Newtonsoft.Json.JsonConvert.SerializeObject(ret);

        }

        /// <summary>
        /// 上传UpdateConfigFile.json的内容
        /// </summary>
        /// <param name="uniquename">唯一标识</param>
        /// <returns>成功返回OK，失败状态码400，返回具体失败原因</returns>
        [HttpPost("UploadConfigJson/{uniquename}")]
        public string UploadConfigJson(string uniquename)
        {
            try
            {
                string ret = "ok";
                _logger.LogInformation( "UploadConfigJson " + uniquename);
                var syncIOFeature = HttpContext.Features.Get<IHttpBodyControlFeature>();
                if (syncIOFeature != null)
                {
                    syncIOFeature.AllowSynchronousIO = true;
                }


                uniquename = "FileServer\\" + uniquename;
                if (Directory.Exists(uniquename))
                {
                    string RelitivePath = uniquename+"\\"+ UpdateConfigFile;
                    using (FileStream writefilestream = new FileStream( RelitivePath, FileMode.Create))
                    {
                        byte[] tmp = new byte[1024];
                        int size = 0;
       
                        while ((size = Request.Body.Read(tmp, 0, tmp.Length)) > 0)
                        {
                            writefilestream.Write(tmp, 0, size);
                        }
                    }
                    ret = $"上传{UpdateConfigFile}成功";


                }
                else
                {
                    Response.StatusCode=400;
                    ret = "不存在该uniquename";
                }
                return ret;
            }
            catch (Exception e)
            {
                Response.StatusCode = 400;
                _logger.LogError(e.Message);
                return e.Message;
            }
        }



        /// <summary>
        /// 获取当前FileServer文件夹下的所有已创建程序信息
        /// </summary>
        /// <returns>字符串用分号隔开,比如   堆场;调度;Program1;Program2;</returns>
        [HttpGet("GetVersions")]
        public string GetVersions()
        {
            try
            {
                List<string> ret = new List<string>();
                _logger.LogInformation( "GetVersions called" );

                string json = string.Empty;
                if (Directory.Exists("FileServer"))
                {
                    var Directories = Directory.GetDirectories("FileServer");
                    foreach (var dir in Directories)
                    {
                        DirectoryInfo directory = new DirectoryInfo(dir);
                        ret.Add(directory.Name);
                    }
                }
                json = Newtonsoft.Json.JsonConvert.SerializeObject(ret);
                return json;
            }
            catch (Exception e)
            {
                Response.StatusCode = 500; 
                _logger.LogError(e.Message);
                return e.Message;
            }

        }


        /// <summary>
        /// Get请求下载一个文件，需要传入两个Querystring 分别是UniqueName 和FileName</summary>
        /// <returns>返回一个文件流</returns>
        [HttpGet("DownLoad")]
        public IActionResult DownLoad()
        {
            try
            {

                var filename = Request.Query["FileName"];//可能是包含子文件夹的相对路径
                var Uniquename = "FileServer\\" + Request.Query["UniqueName"];
                _logger.LogInformation(Request.Host.ToString() + "DownLoad " + Uniquename+" "+ filename);


                var addrUrl = Directory.GetCurrentDirectory() + $"\\{Uniquename}\\" + filename;

                string fileExt = Path.GetExtension(addrUrl);
                var provider = new FileExtensionContentTypeProvider();
                provider.Mappings.Add(".dll", "application/x-msdownload");
                provider.Mappings.Add(".pdb", "application/x-msdownload");
                provider.Mappings.Add(".exe", "application/x-msdownload");
                provider.Mappings.Add(".config", "text/plain");
                provider.Mappings.Add(".bat", "text/plain");
                provider.Mappings.Add(".log", "text/plain");
                provider.Mappings.Add(".ini", "text/plain");
                provider.Mappings.Add(".apk", "application/apk");
                provider.Mappings.Add(".Lic", "text/plain");

                var memi = provider.Mappings[fileExt];
                Response.Headers.Add("Content-Disposition", filename);
                var stream = System.IO.File.OpenRead(addrUrl);
                return File(stream, memi, Path.GetFileName(addrUrl));
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message);
                return null;
            }

            
        }




        /// <summary>
        /// Post请求的方式下载一个文件，暂时不用这个接口
        /// </summary>
        /// <param name="fileInfo"></param>
        /// <returns></returns>
        [HttpPost("DonloadFile")]
        public IActionResult DonloadFile([FromBody] DownFileInfo fileInfo)
        {
            try
            {
                var addrUrl = Directory.GetCurrentDirectory() + @"\Files\" + fileInfo.FileName;
                string fileExt = Path.GetExtension(addrUrl);
                var provider = new FileExtensionContentTypeProvider();
                provider.Mappings.Add(".dll", "application/x-msdownload");
                provider.Mappings.Add(".pdb", "application/x-msdownload");
                provider.Mappings.Add(".exe", "application/x-msdownload");
                provider.Mappings.Add(".config", "text/plain");
                provider.Mappings.Add(".bat", "text/plain");
                var memi = provider.Mappings[fileExt];
                Response.Headers.Add("Content-Disposition", fileInfo.FileName);

                var stream = System.IO.File.OpenRead(addrUrl);
                return File(stream, memi, Path.GetFileName(addrUrl));
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message);
                return null;
            }




        }

        /// <summary>
        /// 上传一个文件 ,必须附带两个Querystring,分别是UniqueName和RelitivePath,代表保存在服务器的目录名和相对路径
        /// </summary>
        /// <returns></returns>
        [HttpPost("UploadFile")]
        public string  UploadFile()
        {
            try
            {
                var files = Request.Form.Files;
                string uniquename = "FileServer\\" + Request.Query["UniqueName"];
                string RelitivePath = Request.Query["RelitivePath"];


                string RelitiveDir = uniquename + "\\" + Path.GetDirectoryName(RelitivePath);
                string filename = "";
                if (!Directory.Exists(uniquename))
                {
                    Directory.CreateDirectory(uniquename);
                }
                if (!Directory.Exists(RelitiveDir))
                {
                    Directory.CreateDirectory(RelitiveDir);
                }
                //files 一次传一个
                foreach (var formfile in files)
                {

                    filename = formfile.FileName;
                    using (Stream stream = formfile.OpenReadStream())
                    using (FileStream writefilestream = new FileStream(uniquename + "\\" + RelitivePath, FileMode.Create))
                    {
                        byte[] tmp = new byte[1024];
                        int size = 0;
                        while ((size = stream.Read(tmp, 0, tmp.Length)) > 0)
                        {
                            writefilestream.Write(tmp, 0, size);
                        }
                    }
                }
                return $"上传{filename}完成";
            }
            catch (Exception e)
            {
                _logger.LogError(e.Message+e.StackTrace);
                return null;
            }
        }

        /// <summary>
        /// 暂时不用
        /// </summary>
        /// <param name="id"></param>
        /// <param name="value"></param>
        [HttpPut("{id}")]
        public void Put(int id, [FromBody] string value)
        {
        }

        /// <summary>
        /// 暂时不用
        /// </summary>
        /// <param name="id"></param>
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }

    public class DownFileInfo
    {
        public string UserID { get; set; }
        public string Passwd { get; set; }
        public string FileName { get; set; }
    }

    [Serializable]
    public class CheckNeedUploadResult
    {
        public bool NeedUpdate;

        public List<string> NeedUploadFiles;

        public CheckNeedUploadResult()
        {
            NeedUploadFiles = new List<string>();
        }

    }

}
